// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using System.Linq;
using NUnit.Framework;
using ValidationAspects;
using ValidationAspects.Exceptions;

namespace TestValidationAspects
{
	[TestFixture]
	public class TestObjectValidation
	{
		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_Validate_throws_for_null_param()
		{
			ObjectValidation.Validate(null);
		}

		[Test]
		public void Test_Validate_calls_correct_validator()
		{
			MockValidatorFactory<Dummy> factory = new MockValidatorFactory<Dummy>();

			typeof(Dummy).ReplaceValidation(new[] {factory});

			Dummy dummy = new Dummy();
			dummy.Validate();

			Assert.AreSame(dummy, factory.Value);
			factory.Context.TestValues(dummy, typeof(Dummy), null, null, null, null);
		}

		[Test]
		public void Test_Validator_returns_successful_ValidationResult()
		{
			MockValidatorFactory<Dummy> factory = new MockValidatorFactory<Dummy>();

			typeof(Dummy).ReplaceValidation(new[] {factory});

			Dummy dummy = new Dummy();

			ValidationResult result = dummy.Validate();

			Assert.IsTrue(result.IsValid);
			Assert.AreEqual(0, result.Messages.Count());
			Assert.IsNull(result.ValidationException);
		}

		[Test]
		public void Test_IsValid_returns_false_for_failure()
		{
			MockValidatorFactory<Dummy> factory = new MockValidatorFactory<Dummy> {Fail = true};

			typeof(Dummy).ReplaceValidation(new[] {factory});

			ValidationResult result = new Dummy().Validate();

			Assert.IsFalse(result.IsValid);
			Assert.AreEqual(1, result.Messages.Count());
			Assert.AreEqual("failed", result.Messages.First());
			Assert.IsNotNull(result.ValidationException);
		}

		[Test]
		public void Test_usage()
		{
			Dummy2 dummy = new Dummy2 {ValidateObject = new InvalidObject()};

			ValidationResult result = dummy.Validate();
			Assert.IsFalse(result.IsValid);
			Assert.AreSame(typeof(ValidateObjectException), ((ValidationContextException)result.ValidationException).Flatten().First().GetType());
		}

		#region Mocks
		public class Dummy2
		{
			[ValidateObject]
			public object ValidateObject { get; set; }
		}

		public class InvalidObject
		{
			[ValidationMethod]
			public static void Validate(InvalidObject invalidObject)
			{
				throw new ValidationException("validation failed");
			}
		}

		public class Dummy {}
		#endregion
	}
}